Ccay.UI.Slider = {};
﻿/**@description slider 组件*/
(function (Slider) {
	var config = {
		distance: 0,
		max: 100, //最大值
		min: 0,   //最小值
		orientation: "horizontal", // 方向，默认 horizontal  水平方向，vertical 为垂直方向
	
		step: 1,	// 每布位移距离
		value: 0,	// 单滑块的当前值
	//	values: null,   //多滑块的值，通过数组模式传值，比如 [20,50]
		numPages : 5,   // 分页数，这个是默认设置，具体分页会根据setp 与 min 、max 来计算，不一定精准
		handle: "<a class='xslider-handle' href='#'></a>",
		tip : true,
		animate: false //是否显示动画,
	//	range: false,   //
	//  fnStart: null, //滑动开始接口
	//  fnSlide: null,  //滑动中接口
	//  fnStop: null,  //滑动结束 接口
	//  fnTip : null  // 显示tip执行接口，可在该接口中自定义tip显示文本
	};
   
   var factory = Slider.Factory = {
   	
   		initOp : function(slider, op){
   			op._animate = true; // 内部动画开关，
   			op.Handle = {
   				refresh : $.Callbacks()
   				
   			};
   		},
   	
		buildHandle : function(slider, op){
			
			var dom = slider.dom, handleCount = ( op.values && op.values.length ) || 1, handles = [];
			
			if ( op.range ) {
				dom.append("<div class='xslider-range xslider-range-{0}'> </div>".formatText( op.range ));
			}
	
			for ( var i = dom.find(".xslider-handle").length; i < handleCount; i += 1 ) {
				handles.push( op.handle );
			}
			
			dom.addClass("xslider xslider-{0}".formatText( op.orientation )).append( handles.join(""));
			
			slider.getHandle().each(function(i){
				$(this).data("handle.index",i);
			})
			
			!$("#xsliderTip")[0]  && $("<div id=xsliderTip ></div>").appendTo(document.body);
		},
		
		
		EventBinder : {
			bindKeyEvent : function(slider, op){
				slider.getHandle().click(function( event ) { 
					//注册滑块A标签的点击事件，并阻止A标签默认事件行为的触发。 
					event.preventDefault();
				}).hover(function() {
						if ( !op.disabled ) {
							$( this ).addClass("handle-hover");
						}
					}, function( event ) {
						$( this ).removeClass("handle-hover");
				}).focus(function( event ){
					if ( !op.disabled ) {
						$(this).addClass("handle-focus");
					} else {
						$(this).blur();
					}
				}).blur(function( event ){
					$( this ).removeClass("handle-focus");
				});
				
				
				slider.getHandle().keydown(function( event ){
					
					if( op.disabled ){
						return;
					}
					
					var ret = true, index = $( this ).data( "handle.index" ), allowed,curVal,newVal,step = op.step;
					
					curVal = newVal = slider.getValue( index );
	
					switch ( event.keyCode ) {
						case 36:		//HOME
						case 35:		//END	
						case 33:		//PageUp
						case 34:		//PageDown
						case 38:		//UP
						case 39: 		//RIGHT
						case 40:		//DOWN
						case 37:		//LEFT
							ret = false;
							//按键滑行状态开启
							if ( !op._keySliding ) {
								op._keySliding = true;
								$(this).addClass( "handle-active" );
								allowed = Slider.Helper.start(slider, index );
								if ( allowed === false ) {
									return;
								}
							}
							break;
					}
		
					switch ( event.keyCode ) {
						case 36:		//HOME
							newVal = op.min;
							break;
						case 35:		//END	
							newVal = op.max;
							break;
						case 33:		//PageUp
							newVal = Slider.Helper.fixValue( curVal - (op.max - op.min) / op.numPages, index, op);
							break;
						case 34:		//PageDown
							newVal = Slider.Helper.fixValue( curVal + (op.max - op.min) / op.numPages, index, op);
							break;
						case 38:		//UP
						case 39: 		//RIGHT
							if ( curVal === op.max ) {
								// 如果已经到边缘，则直接返回，不做处理
								return;
							}
							newVal = Slider.Helper.fixValue( curVal + step, index, op);
							break;
						case 40:		//DOWN
						case 37:		//LEFT
							if ( curVal === op.min ) {
								// 如果已经到边缘，则直接返回，不做处理
								return;
							}
							newVal =  Slider.Helper.fixValue( curVal - step, index, op );
							break;
					}
		
					Slider.Helper.slide(slider, newVal, index);
		
					return ret;
	
				}).keyup(function(event){
					
					var index = $(this).data( "handle.index" );
					
					if ( op._keySliding ) {
						op._keySliding = false;
						Slider.Helper.stop( slider, index );
						$(this).removeClass( "handle-active" );
					}
				});
				
			},
			
			bindMouseEvent : function(slider, op){
				
				var dom = slider.dom, handle = slider.getHandle()
				
				dom.bind("mousedown", function(event){
					if( op.disabled ){
						return;
					}
					Slider.Helper.mouseStart(slider, event);
					return false;
				})
			
			}
			
		}

    };
    
    Slider.Helper = {
    
    	
    	fixValue : function(newVal, index, op){
    		if(op.values){
    			var otherVal = op.values[index ? 0 : 1];
    			if ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) ) {
					newVal = otherVal;
				}
    			newVal =  newVal > op.max ? op.max : (newVal < op.min ? op.min : newVal);
    			
    		}else{
    			newVal =  newVal > op.max ? op.max : (newVal < op.min ? op.min : newVal);
    		}
    		
    		if(newVal != op.min && newVal != op.max){
	    		var val = ( newVal - op.min ) % op.step;
	    		
	    		if( val ){
		    		newVal -= val;
		    		
		    		newVal += (val * 2 > op.step) ? op.step : ( 0 );
	    		}
    		}
    
    		return newVal;
    	
    	},
    	
    	mouseStart : function(slider, event){
    		var dom = slider.dom, op = slider.op, handle = slider.getHandle(),
    		handleIndex = 0, offset = dom.offset(), newVal, handleIndex;
    		if(op.orientation === "horizontal"){
    			newVal = op.min + (event.pageX - offset.left ) / dom.width() * (op.max - op.min) ;
    		}else{
    			newVal = op.max - (event.pageY - offset.top ) / dom.height() * (op.max - op.min);
    		}
			
    		//算出需要移动的滑块索引
			handleIndex = op.values ?  ( (newVal < (op.values[1] - op.values[0])/2 + op.values[0]) ? 0 : 1) : 0;
			$(handle[ handleIndex ]).addClass("handle-active");
			var target = $.getEventTarget(event)
			if(!target.hasClass("xslider-handle") && target.parents("a.xslider-handle").length == 0){
				this.slide(slider, newVal, handleIndex);
			}
			var num = 0;
			op._animate = false;
			$(document).on("mousemove.slide", function( event ){
				//优化性能
				if( (++num) % 3 === 0){
					Slider.Helper.mouseMove(event, slider, handleIndex);
					op.tip && Slider.Helper.showTip(slider, handleIndex);
				}
				return false;
    		}).one("mouseup.slide", function(){
    			Slider.Helper.mouseStop(slider, handleIndex);
    		}).one('selectstart',function(){return false;});
    	},
    	
    	mouseStop : function(slider, handleIndex){
			$(document).off("mousemove.slide");
			slider.getTip().hide();
			var active = slider.getHandle().removeClass("handle-active")[handleIndex];
			if($(active).is(":visible")){
				active.focus();
			}
			slider.op._animate = true;
			
    	},
    	
    	
    	mouseMove :function(event, slider, handleIndex){
			if(!$.browser.msie || $.browser.version > 8 || event.button){
				
				var dom = slider.dom, op = slider.op, handle = slider.getHandle(), offset = dom.offset(), newVal ;
    			
	    		if(op.orientation === "horizontal"){
	    			newVal = op.min + (event.pageX - offset.left) / dom.width() * (op.max - op.min);
	    		}else{
	    			newVal = op.max - (event.pageY - offset.top) / dom.height() * (op.max - op.min);
	    		}
	    		
	    		this.slide(slider, newVal, handleIndex)

			}else{
				this.mouseStop(slider, handleIndex);
			}
			
    	},
    	
    	start : function(slider, index){
    		var fnStart = slider.op.fnStart;
    		fnStart && fnStart.call(slider, {
				handle: $( slider.getHandle()[ index ] ),
				value: slider.getValue(index)
			});
    	},
    	
    	
    	stop : function(slider, index){
    		var fnStop = slider.op.fnStop;
    		fnStop && fnStop.call(slider, {
				handle: $( slider.getHandle()[ index ] ),
				value: slider.getValue(index)
			});
    	},
    	

		slide: function(slider, newVal, index) {
			var op = slider.op, otherVal, newValues, allowed;
			
			newVal = Slider.Helper.fixValue(newVal, index, op)
			//区域选择清空处理
			if ( op.values ) {
				//当值改变
				if ( newVal !==  op.values[index] ) {
					
					newValues = [].concat(op.values);
					
					newValues[index] = newVal;
					
					allowed = op.fnSlide && op.fnSlide.call(slider, {
						handle : $(slider.getHandle()[index]),
						value  : newVal,
						values : newValues
					});
					
					// 修改值
					if ( allowed !== false ) {
						op.values[index] = newVal;
					}
				}
			} else {
				//单值处理，如果值改变，则除非fnSlide并传递改变后的值，如果fnSlide返回false，则不做修改
				if ( newVal !== op.value ) {
					allowed = op.fnSlide && op.fnSlide.call(slider, {
						handle : $(slider.getHandle()[index]),
						value  : newVal
					});
					if ( allowed !== false ) {
						op.value = newVal;
					}
				}
			}
			
			slider.refresh();
		},
		
		
		showTip : function(slider, handleIndex){
			var op = slider.op, currHandle = op.values ? $(slider.getHandle()[handleIndex]) : slider.getHandle();
			var _set = currHandle.offset(), value =  op.values ? op.values[handleIndex] : op.value;
			_set.top = _set.top - 25;
			value = op.fnTip ? op.fnTip.call(slider, value) : value;
			
			if(value !== false){
				slider.getTip().show().css(_set).text(value);
			}
		
		},
		
		/** 根据当前值刷新滑块状态
		 */
		refresh : function(slider ){

			var op = slider.op, dom = slider.dom, range = op.range,
				animate =  op._animate ? op.animate : false,
				valPercent, _set = {}, lastValPercent, domHandle = slider.getHandle(), domRange = slider.getRange().stop( 1, 1 );
	
			if ( op.values ) {
				domHandle.each(function( handleIndex ) {
					// 得到当前handle 所在整个slider的百分比数
					valPercent = ( op.values[handleIndex] - op.min ) / ( op.max - op.min ) * 100;
					// 根据 orientation的参数不同（横向或竖向），设置不同的定位方式 left 或  bottom
					_set[ op.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
					
					//停止原有动画,并开始刷新新样式或执行动画
					$( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, op.animate );
					if ( range === true ) {
						
						if ( op.orientation === "horizontal" ) {
							if ( handleIndex === 0 ) {
								domRange[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, op.animate );
							}else if( handleIndex === 1 ) {
								domRange[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: op.animate } );
							}
						} else {
							if ( handleIndex === 0 ) {
								domRange[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, op.animate );
							}else if( handleIndex === 1 ) {
								domRange[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: op.animate } );
							}
						}
					}
					lastValPercent = valPercent;
				});
			} else {
				
				var value = slider.getValue(), min = op.min, max = op.max, _setFix;
				
				valPercent = ( min !== max ) ? ( value - min ) / ( max - min ) * 100 : 0;
				
				_set[ op.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";

				domHandle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set , op.animate );
	
				if ( range === "min" && op.orientation === "horizontal" ) {
					
					domRange[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, op.animate );
					
				}else if( range === "max" && op.orientation === "horizontal" ) {
					
					domRange[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: op.animate } );
					
				}else if( range === "min" && op.orientation === "vertical" ) {
					
					domRange[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, op.animate );
					
				}else if( range === "max" && this.orientation === "vertical" ) {
					
					domRange[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: op.animate } );
				}
			}
		
		}
    }

	
    var manager = {
    	
		/** @description 获取拖拽的滑块 
	     *  @return {JQDom}
	     */
		getHandle: function (){
	        return DomClass.getProp( this, this.dom, 'handle', 'a.xslider-handle',true);
	    },
	    
	    getRange : function(){
	    	 return DomClass.getProp( this, this.dom, 'range', 'div.xslider-range', true);
	    },
	    
	    getTip :function(){
	    	 return DomClass.getProp( this, $(document), 'tip', '#xsliderTip',true);
	    },

	    disabled : function(enable){
	    	if(enable){
	    		this.dom.removeClass("disabled");
	    	}else{
	    		this.dom.addClass("disabled");
	    	}
	    	this.op.disabled = !enable;
	    },
	    
	    readonly : function(writeable){
	    	this.op.disabled = !writeable;
	    },
			
		//设置值
		setValue : function( value, i){
			var op = this.op;
			if( op.values ){
				if( $.isArray(value) ){
					op.values = value;
				}else{
					op.values[i || 0] = Slider.Helper.fixValue(value, i || 0, op);
				}
			}else{
				op.value = Slider.Helper.fixValue(value, null, op);
			}
			this.refresh();
		},
			
		getValue : function( i ){
			var op = this.op;
			return op.values && !isNaN(i) ? op.values[i] : (op.values ? op.values : op.value); 
		
		},
			
		refresh: function(op) {
			op && $.extend(this.op, op);
			Slider.Helper.refresh(this);
		},
		
		resize : function(){
			this.op.Handle.refresh.fire(this, this.op);
		}

	};
    
    var flow = {


		init : function( slider, op ){
			factory.initOp(slider, op);
		},
    	build : function( slider, op )
    	{
    		factory.buildHandle( slider, op );
    		
    		slider.refresh();
    	},
    	bindEvent : function( slider, op ){

    		factory.EventBinder.bindKeyEvent( slider, op );
    		factory.EventBinder.bindMouseEvent( slider, op );
    	}
    };
    
    
    var XSlider = Ccay.UI.XControl( "XSlider", flow, config, manager );
    
	/** 滑块 初始化*/
     $.fn.slider = function (op) {
     	this.each(function(){
     		var ctr = $(this);
     		if(!ctr.attr("init")){
     			new XSlider( $(this), op);
     			!ctr.attr("init",true)
     		}
     	})
        return this;
    }
    
        /** MessageBox 插件部分 */
	Ccay.UI.XControl.addPlugin( "XSlider", "XScroll", {
	    preInit: function ( slider, op ) {
	    	if( op.scroll ){
	    		Scroll.init( slider, op);
	    	}
	    },
	    
	    build : function( slider, op ) {
	    	if(  op.scroll ){
	    		
	    		Scroll.initStyle( slider, op);
				Scroll.bindEvent( slider, op);
	    	}
	    }
	     
	 } );
	 
	 var Scroll = {
	 
	 		init : function(slider, op){
	 			op.handle = "<div class='xslider-handle-parent'><a class='xslider-handle' href='#'><span class='handle-icon' /></a></div>";
	 			if(!op.fnSlide){
	 				op.fnSlide = this.scroll;
	 			}
	 			this.buildScroll( slider, op )
	 		},
	 		
	 		bindEvent : function(slider, op){
	    		var time ;
				op.Handle.refresh.add(this.initStyle);
				
		    	slider.dom.addClass("xslider-scroll").parent().children(".scroll-button").mousedown(function(event){
		    		
	    			var step = $.getEventTarget(event).is(".scroll-left") ? -op.step : op.step;
	    			
	    			
	    			var newVal = Slider.Helper.fixValue( op.value + step, 0, op);
	    			var callee = arguments.callee;
	    			
	    			op._buttonSliding = setTimeout( function(){ callee(event); },  time = time ? 150 : 500);
	    			
	    			Slider.Helper.slide(slider, newVal, 0);
	    			
	    			return false;
	    			
	    		}).bind("mouseup mouseout",function(event){
	    			window.clearTimeout(op._buttonSliding);
	    		}).one('selectstart',function(){return false;});
	    		
	    		$(op.scroll.target).parent().scroll(function(event){
	    			var target = $(op.scroll.target), panel= $(this), left = panel.scrollLeft();
	    			if(left > 0){
	    				slider.setValue(left / (target.width() -  panel.width()) * ( op.max - op.min ));
	    			}
	    		});
	 		},
	 		
	 		scroll : function(data){
				var op = this.op, target = $(op.scroll.target);
				var valPercent = ( data.value - op.min ) / ( op.max - op.min ) * 100;
				var left = valPercent / 100 * (target.width() -  target.parent().width());
				target.parent().scrollLeft(left);
	 		},
	 		
	 		initStyle : function(slider, op){
				var dom = slider.dom, handle = slider.getHandle(), handleWidth = op.scroll.width || 100 ;
				dom.width(dom.parent().width() - 40);
	    		handle.width(handleWidth).css("margin-left", -handleWidth / 2);
	    		
	    		dom.find("div.xslider-handle-parent").width( dom.width() - handleWidth);
	 		},
	 		
	 		buildScroll : function(slider, op){
	 			var dom = slider.dom.wrap("<div class='scroll-bar scroll-bar-{0}' />".formatValue(op.orientation));
	 			dom.parent().append("<a class='scroll-button scroll-left' />").append("<a class='scroll-button scroll-right' />");
	 		}
	 
	 } 
} )(Ccay.UI.Slider);

